﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Data;
using System.Drawing;
using System.IO;
using System.Xml;
using FLTools.ComponentModel;
using FLCore;

namespace FLRuntime
{
    internal class FLPreview
    {
        public FLPreview(string xomlFile, string ruleFile, Guid flInstanceId, object[] _clientInfo, string _currentAcitivity, DataSet hostDataSet, string _roleID, string _orgKind, object[] keyValues)
        {
            clientInfo = _clientInfo;
            currentAcitivity = _currentAcitivity;
            role = _roleID;
           // orgKind = _orgKind;
            //create or find instance
            if (flInstanceId.Equals(Guid.Empty))
            {
                instance = Global.FLRuntime.CreateFLInstance(flInstanceId, xomlFile, ruleFile, _clientInfo, hostDataSet, _orgKind);
                currentAcitivity = instance.RootFLActivity.ChildFLActivities[0].Name;
            }
            else
            {
                instance = Global.FLRuntime.GetFLInstance(flInstanceId, _clientInfo);
                xomlFile = instance._flDefinitionFile;
            }
            if (hostDataSet != null)
            {
                instance._hostDataSet = hostDataSet;//设置host表
            }
            else
            {
                instance._hostDataSet = HostTable.GetHostDataSet(instance, keyValues, _clientInfo);
            }

            string message = SysMsg.GetSystemMessage((SYS_LANGUAGE)(((object[])(_clientInfo[0]))[0]), "FLDesigner", "FLDesigner", "FLPreview");
            userText = message.Split(',')[0];
            roleText = message.Split(',')[1];
            Document.Load(xomlFile); //载入xoml
        }

        private string userText;

        private string roleText;

        private FLInstance instance;
        /// <summary>
        /// 流程实例
        /// </summary>
        public FLInstance Instance
        {
            get { return instance; }
        }

        private object[] clientInfo;
        public object[] ClientInfo
        {
            get { return clientInfo; }
        }

        //private string orgKind;

        public string OrgKind
        {
            get { return ((IFLRootActivity)Instance.RootFLActivity).OrgKind; }
        }

        private string role;

        public string Role
        {
            get { return role; }
        }

        public string User
        {
            get { return (string)(((object[])ClientInfo[0])[(int)ClientInfoType.LoginUser]); }
        }
	

        private string currentAcitivity;
        public string CurrentAcitivity
        {
            get { return currentAcitivity; }
        }

        private XmlDocument document= new XmlDocument();

        public XmlDocument Document
        {
            get { return document; }
        }
	
        const string DESIGNER_FILE = "FLDesigner.exe";

        public Image CreatePreviewImage()
        {
            //ReviewPrevious
            ReviewPrevious();
            //markcurrent
            MarkCurrent();
            //PreviewNext
            PreviewNext();

            RemoveApprove();
            //saveXoml
            string filename =  Path.GetRandomFileName();
            string filepath = Path.GetTempPath() + "\\" + filename;
            //string filename = "c:\\1.xoml";
            Document.Save(filepath);

            string designPath = string.Format("{0}\\{1}", EEPRegistry.Server, DESIGNER_FILE);
            if (!File.Exists(designPath))
            {
                designPath = string.Format("{0}\\FLDesigner\\{1}", Path.GetDirectoryName(EEPRegistry.Server), DESIGNER_FILE);
                if (!File.Exists(designPath))
                {
                    throw new Exception("Can not find FLDesigner.exe");
                }
            }

            System.Diagnostics.Process process = System.Diagnostics.Process.Start(designPath, filename);
            process.WaitForExit(30000);
      
      //      return (Bitmap)SaveImage(filename);
            if (File.Exists(filepath + ".bmp"))
            {
                Bitmap bmp = (Bitmap)Image.FromFile(filepath + ".bmp");
                return bmp;
            }
            return null;
        }

        private XmlNode FindNode(XmlNode node, string name)
        {
            if (node != null)
            { 
                 XmlAttribute att = node.Attributes["x:Name"];
                 if (att != null && att.Value.Equals(name))
                 {
                     return node;
                 }
                 foreach (XmlNode child in node.ChildNodes)
                 {
                     XmlNode nd = FindNode(child, name);
                     if (nd != null)
                     {
                         return nd;
                     }
                 }
            }
            return null;
        }

        //替换内容
        private bool ReplaceName(XmlNode document, string oldName, string newName, bool current, bool pass)
        {
            XmlNode node = FindNode(document, oldName);
            if (node != null)
            {
                XmlAttribute att = node.Attributes["x:Name"];
                if (!string.IsNullOrEmpty(newName))
                {
                    att.Value = att.Value + "_" + newName; //换名字
                }

                if (current)
                {
                    XmlNode currentNode = node.OwnerDocument.CreateElement("FLCurrent", node.NamespaceURI);
                    XmlAttribute currentAtt = node.OwnerDocument.CreateAttribute("x:Name");
                    currentAtt.Value = att.Value;
                    currentNode.Attributes.Append(currentAtt);
                    node.ParentNode.InsertAfter(currentNode, node);
                    node.ParentNode.RemoveChild(node);
                }
                else if (pass)
                {
                    XmlNode passNode = node.OwnerDocument.CreateElement("FLPass", node.NamespaceURI);
                    XmlAttribute passAtt = node.OwnerDocument.CreateAttribute("x:Name");
                    passAtt.Value = att.Value;
                    passNode.Attributes.Append(passAtt);
                    node.ParentNode.InsertAfter(passNode, node);
                    node.ParentNode.RemoveChild(node);
                }
                return true;
            }
            return false;
        }

        private List<string> ApproveNames = new List<string>();

        //FLAprrove插入新节点用
        private bool InsertApproveStand(XmlNode document, string approve, string name)
        {
            XmlNode node = FindNode(document, approve);
            if (node != null)
            {
                XmlNode standNode = node.OwnerDocument.CreateElement("FLStand", node.NamespaceURI);
                XmlAttribute att = node.OwnerDocument.CreateAttribute("x:Name");
                att.Value = name;
                standNode.Attributes.Append(att);
                node.ParentNode.InsertBefore(standNode, node);

                if (!ApproveNames.Contains(approve))
                {
                    ApproveNames.Add(approve);
                }

                return true;
            }
            return false;
        }

        private void RemoveApprove()
        {
            foreach (string name in ApproveNames)
            {
                RemoveApprove(Document.DocumentElement, name);
            }
        }

        private void RemoveApprove(XmlNode document, string approve)
        {
            XmlNode node = FindNode(document, approve);
            if (node != null)
            {
                node.ParentNode.RemoveChild(node);
            }
        }

        private void AddSendTo(string activityName, SendTo send)
        {
            AddSendTo(activityName, send, false, false);
        }

        private void AddSendTo(string activityName, SendTo send, bool current, bool pass)
        {
            string newName = "Unknown";
            FLActivity activity = Instance.RootFLActivity.GetFLActivityByName(activityName);
            if (activity != null)
            {
                if (activity is IFLApproveBranchActivity)
                {
                    activityName = activityName.Replace("-", "_");
                    InsertApproveStand(Document.DocumentElement, (activity as IFLApproveBranchActivity).ParentActivity, activityName);
                }
                else if (activity is ISupportFLDetailsActivity)
                {
                    if (!string.IsNullOrEmpty((activity as ISupportFLDetailsActivity).SendToId2))
                    { 
                        //找不到好方法,直接从名字里找
                        int index = activityName.LastIndexOf('_');
                        if (index > 0)
                        {
                            activityName = activityName.Substring(0, index);
                            send = new SendTo(string.Empty, string.Empty);
                        }
                    }
                }
            }

            //为Activity加上待办者的名字
            
            if (!string.IsNullOrEmpty(send.UserID))
            {
                string name = Global.GetUserName(send.UserID, ClientInfo);

                newName = string.Format("{0}_{1}",userText, name);
            }
            else if (!string.IsNullOrEmpty(send.RoleID))
            {
                string name = Global.GetGroupName(send.RoleID, ClientInfo);
                if (name.Contains("/"))
                {
                    name = name.Split('/')[0];
                }
                newName = string.Format("{0}_{1}", roleText, name);
            }
            ReplaceName(Document.DocumentElement, activityName, newName, current, pass);
        }


        private class SendTo
        {
            public SendTo(string role, string user)
            {
                roleID = role;
                userID = user;
            }

            private string roleID;

            public string RoleID
            {
                get { return roleID; }
                set { roleID = value; }
            }

            private string userID;

            public string UserID
            {
                get { return userID; }
                set { userID = value; }
            }
        }

        private enum SendToType
        { 
            Role,
            User
        }

        private enum StatusType
        { 
            /// <summary>
            /// 加签
            /// </summary>
            A,
            /// <summary>
            /// 通知
            /// </summary>
            F,
            /// <summary>
            /// 正常
            /// </summary>
            N,
            /// <summary>
            /// 取回
            /// </summary>
            NF,
            /// <summary>
            /// 退回
            /// </summary>
            NR,
            /// <summary>
            /// 验证
            /// </summary>
            V,
            /// <summary>
            /// 废除
            /// </summary>
            X,
            /// <summary>
            /// 结案
            /// </summary>
            Z
        }

        const string SELECT_TODOHIS_SQL = "SELECT S_STEP_ID, D_STEP_ID,STATUS,S_USER_ID FROM SYS_TODOHIS Where (LISTID = '{0}')";

        private void ReviewPrevious()
        { 
            //从todohis中取
            EEPRemoteModule remoteModule = new EEPRemoteModule();
            string sql = string.Format(SELECT_TODOHIS_SQL, Instance.FLInstanceId);
            object[] objs = remoteModule.CallMethod(ClientInfo, "GLModule", "ExcuteWorkFlow", new object[] { sql });
            if (objs[0].ToString() == "0")
            {
                DataSet dataSet = (DataSet)objs[1];
                if (dataSet.Tables.Count > 0)
                {
                    DataTable table = dataSet.Tables[0];
                    //计算退回和取回
                    for (int i = 0; i < table.Rows.Count; i++)
                    {
                        DataRow row = table.Rows[i];
                        if (row["STATUS"].Equals(StatusType.NF.ToString()) || row["STATUS"].Equals(StatusType.NR.ToString()))
                        {
                            string activityName = row["D_STEP_ID"].ToString();//退回或取回到哪一步
                            //找到那一步
                            int returnIndex = -1;
                            for (int j = 0; j < i; j++)
                            {
                                DataRow previousRow = table.Rows[j];
                                if (previousRow.RowState != DataRowState.Deleted)
                                {
                                    if (previousRow["S_STEP_ID"].Equals(activityName))
                                    {
                                        returnIndex = j;
                                    }
                                }
                            }
                            if (returnIndex != -1) //删除那一步以后的资料
                            {
                                for (int j = returnIndex; j < i; j++)
                                {
                                    DataRow previousRow = table.Rows[j];
                                    if (previousRow.RowState != DataRowState.Deleted)
                                    {
                                        previousRow.Delete();
                                    }
                                }
                            }
                        }
                    }
                    for (int i = 0; i < table.Rows.Count; i++)
                    {
                        DataRow row = table.Rows[i];
                        if (row.RowState != DataRowState.Deleted)
                        {
                            if (row["STATUS"].Equals(StatusType.N.ToString()))
                            {
                                string activityName = row["S_STEP_ID"].ToString();
                                string sender = row["S_USER_ID"].ToString();
                                AddSendTo(activityName, new SendTo(string.Empty, sender), false, true);
                            }
                        }
                    }
                }
            }
        }

        private void MarkCurrent()
        {
       //     string useid = (string)(((object[])ClientInfo[0])[(int)ClientInfoType.LoginUser]);
            AddSendTo(CurrentAcitivity, new SendTo(string.Empty, User), true, false);
        }

        private void PreviewNext()
        { 
            //通过计算
            
            //flinstance.hostDataSet要改写
            SendTo send = new SendTo(Role, User);
            GetNextActivity(send, CurrentAcitivity);
        }

        //递归
        private void GetNextActivity(SendTo from, string AcitivityName)
        {
            List<FLActivity> activitys = instance.GetNextFLActivities(AcitivityName, from.UserID, from.RoleID);
            foreach (FLActivity activity in activitys)
            {
                if (activity is IEventWaiting)
                {
                    if (activity is ISupportFLDetailsActivity)
                    {
                        if (!string.IsNullOrEmpty((activity as ISupportFLDetailsActivity).SendToId2))
                        {
                            continue;//fldetail跳过
                        }
                    }

                    SendTo send = GetSendTo(activity as IEventWaiting, from);
                    AddSendTo(activity.Name, send);
                    GetNextActivity(send, activity.Name);
                }
            }
        }

        private SendTo GetSendTo(IEventWaiting activity, SendTo from)
        {
            switch (activity.SendToKind)
            {
                //user
                case SendToKind.Applicate: return new SendTo(string.Empty, Instance.Creator);
                case SendToKind.User:
                    {
                        string user = string.IsNullOrEmpty(activity.SendToUser) ? string.Empty : activity.SendToUser.Split(';')[0].Trim();
                        return new SendTo(string.Empty, user);
                    }
                case SendToKind.RefUser:
                    {
                        string user = Instance._hostDataSet.Tables[0].Rows[0][activity.SendToField].ToString();
                        return new SendTo(string.Empty, user);
                    }
                case SendToKind.Role:
                    {
                        string role = string.IsNullOrEmpty(activity.SendToRole) ? string.Empty : activity.SendToRole.Split(';')[0].Trim();
                        return new SendTo(role, string.Empty);
                    }
                case SendToKind.RefRole:
                    {
                        string role = Instance._hostDataSet.Tables[0].Rows[0][activity.SendToField].ToString();
                        return new SendTo(role, string.Empty);
                    }
                case SendToKind.Manager:
                    {
                        return GetManager(from);
                    }
                case SendToKind.RefManager:
                    {
                        string role = string.Empty;
                        if (activity is FLApproveActivity && (activity as FLApproveActivity).I > 1)
                        {
                            role = from.RoleID;
                        }
                        else
                        {
                            role = Instance._hostDataSet.Tables[0].Rows[0][activity.SendToField].ToString();
                        }
                        return GetManager(new SendTo(role, string.Empty));
                    }
                case SendToKind.ApplicateManager:
                    {
                        return GetManager(new SendTo(string.Empty, Instance.Creator));

                    }
            }
            return new SendTo(string.Empty, string.Empty);
        }

        private SendTo GetManager(SendTo send)
        {
            string role = string.Empty;
            if (!string.IsNullOrEmpty(send.RoleID))
            {
                role = send.RoleID;
            }
            else if (!string.IsNullOrEmpty(send.UserID))
            {
                List<string> roleIds = Global.GetRoleIdsByUserId(send.UserID, ClientInfo);
                if (roleIds.Count > 0)
                {
                    role = roleIds[0];
                }
            }
            if (!string.IsNullOrEmpty(role))
            {
                role = Global.GetManagerRoleId(role, OrgKind, ClientInfo);
                return new SendTo(role, string.Empty);
            }
            return new SendTo(string.Empty, string.Empty);
        }
    }
}
